import time
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait


class BasePage:

    def __init__(self, browser:str):
        """
        初始化浏览器
        :param browser: 浏览器类型
        """
        # if browser=='Chrome':
        #     driver = webdriver.Chrome()
        # elif browser=='Firefox':
        #     driver = webdriver.Firefox()
        # elif browser=='Edge':
        #     driver = webdriver.Edge()
        # 利用反射技术生成浏览器对象
        self.driver = getattr(webdriver,browser)()

    def open(self, url, seconds=10):
        """
        打开目标页面
        :param url: 页面地址
        :return: None
        """
        # 打开目标页面
        self.driver.get(url)
        # 窗口最大化
        self.driver.maximize_window()
        # 隐式等待
        self.driver.implicitly_wait(seconds)

    def locate(self,by,value):
        """
        将自定义的定位方式转变为Selenium标准定位方式
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :return: tuple-Selenium标准定位方式，形如 (By.ID, 'kw)
        """
        if by in ['i','id']:
            locator = (By.ID, value)
        elif by in ['n','name']:
            locator = (By.NAME, value)
        elif by in ['c','class_name']:
            locator = (By.CLASS_NAME, value)
        elif by in ['t','tag_name']:
            locator = (By.TAG_NAME, value)
        elif by in ['l','link_text']:
            locator = (By.LINK_TEXT, value)
        elif by in ['p','partial_link_text']:
            locator = (By.PARTIAL_LINK_TEXT, value)
        elif by in ['x','xpath']:
            locator = (By.XPATH, value)
        elif by in ['css','css_selector']:
            locator = (By.CSS_SELECTOR, value)
        return locator

    def locate_element(self, by, value, timeout=5, poll_frequency=0.2):
        """
        定位单个元素
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :param timeout: 最大等待时间， 单位是秒
        :param poll_frequency: 检查时间间隔， 单位是秒
        :return: WebElement 定位到的元素
        """
        # 获取元素标准定位方式
        locator = self.locate(by, value)
        # self.driver.find_element(locator[0],locator[1])
        # self.driver.find_element(*locator)
        # 定位元素
        return WebDriverWait(self.driver,timeout,poll_frequency).until(expected_conditions.presence_of_element_located(locator))

    def locate_elements(self, by, value, timeout=5, poll_frequency=0.2):
        """
        定位多个元素
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :param timeout: 最大等待时间， 单位是秒
        :param poll_frequency: 检查时间间隔， 单位是秒
        :return: list, 元素列表
        """
        # 获取元素标准定位方式
        locator = self.locate(by, value)
        # 定位元素
        n = 1 / poll_frequency * timeout
        # 自定义显示等待
        while n:
            # 定位元素
            try:
                elements = self.driver.find_elements(*locator)
                # 判断列表是否为空
                if elements:
                    return elements
            except:
                pass
            # 强制等待
            sleep(poll_frequency)
            n = n - 1


        return None

    def type(self, by, value, text):
        """
        向元素中输入文本
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :param text: 输入的文本
        :return: None
        """
        # 定位元素
        element = self.locate_element(by, value)
        # 操作元素
        element.send_keys(text)

    def click(self, by, value):
        """
        单击元素
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :return: None
        """
        # 定位元素
        elements = self.locate_elements(by, value)
        # 操作元素
        if elements:
            elements[0].click()

    def switch_to_frame(self, by, value):
        """
        切换到iframe中
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :return: None
        """
        # 定位iframe元素
        iframe = self.locate_element(by, value)
        # 切换到iframe中
        self.driver.switch_to.frame(iframe)

    def select_by_index(self, by, value, index):
        """
        根据下标进行选择
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :param index: 下标， 从0开始
        :return: None
        """
        # 定位元素
        select = self.locate_element(by, value)
        options = Select(select)
        # 根据下标进行选择，下标从0开始
        options.select_by_index(index)

    def select_by_value(self, by, value, element_value):
        """
        根据value属性的值进行选择
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :param element_value: value属性的值
        :return: None
        """
        # 定位元素
        select = self.locate_element(by, value)
        options = Select(select)
        # 根据vlaue属性的值
        options.select_by_value(element_value)

    def select_by_visible_text(self, by, value, visible_text):
        """
        根据可见文本进行选择
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :param visible_text: 可见文本
        :return: None
        """
        # 定位元素
        select = self.locate_element(by, value)
        options = Select(select)
        # 根据可见文本进行选择
        options.select_by_visible_text(visible_text)

    def close(self):
        """
        关闭当前窗口
        :return: None
        """
        self.driver.close()

    def wait(self, seconds):
        """
        强制等待
        :param seconds: 等待的时间，单位是秒
        :return: None
        """
        time.sleep(seconds)


    def assertEqual(self, by, value, expected):
        """
        断言相等
        :param by: 自定义定位方式
        :param value: 定位方式对应的值
        :param expected: 期望值
        :return: None
        """
        # 定位元素
        elements = self.locate_elements(by, value)
        # 断言相等
        assert elements[-1].text == expected, '断言失败'
    def screenshot(self):
        """
        获取屏幕截图
        :return: None
        """
        # 获取时间戳
        timestamp = time.strftime('%Y-%m-%d_%H-%M-%S')
        # 截图
        self.driver.save_screenshot(r'ranzhi/report/img/img_{0}.png'.format(timestamp))

if __name__ == '__main__':
    BasePage('Chrome')
    sleep(2)
